#!/usr/bin/bash
#
#-------HEADER---------------------------------------------------------------------|
#AUTOR
#  Jefferson Rocha <lrcjefferson@gmail.com>
#
#
#DATA DE CRIAÇÃO
#  31/01/2018
#
#
#LICENÇA
#  MIT
#  https://raw.githubusercontent.com/dunee/backup/master/LICENSE
#
#
#DESCRIÇÃO
#  dunee é um simples programa em Shell com interface dialog para backup em sistema
#  GNU/Linux.
#  São necessárias algumas dependências para ser executado com exito, sendo elas:
#  (rsync, dialog, tar, xf, bash)
#
#
#ARQUIVOS DE AJUDA.
#  -Todos arquivos estão localizados em /etc/dunee  
#  menu-principal.txt
#  -Executavel se encontra em /usr/sbin
#
#
#***NOTAS DE DESENVOLVIMENTO***
# -Usar somente um comando por linha
# -Usar somente 1 parâmetro no dialog por linha, não se importando com o tamanho
# de linhas.
# -Usar chamadas (funções, váriaveis, arrays) em inglês.
# -Comentários devem ser em português do brasil.
# -Se a linha é "complexa" deixe um comentário.
# -Para condicionais '[ ]' ou 'test' simples, estamos em bash, use a nova sintaxe
# '[[ ]]'
#
#
#CHANGELOG
# V0.1 (Jefferson Rocha)
#    Iniciado projeto em 31/01/2018
#
# V0.2 (Jefferson Rocha)
#   -Agora tem suporte a md5 no backup básico
#
#   -Adicionado condicional no bloco (dir_if_backup e dir_of_backup) testa se os
#   diretorios tem permissão de Escrita.
#
#   -Reformulado todo código, status de sáida estavam com problemas.
#
#   -Adicionado opção para envio remoto com scp /Falta o recebimento.
#
#   -Agora o programa tem logs em '/tmp', agora mostra os erros.
#
#   -O bloco (básico) foi dividido em 3 funções para não repitir código no decorrer
#   do programa, os blocos são:
#   'if_dir, of_dir e create_backup_basic' a chamada basic_mod ainda continua, para
#   fazer as chamadas das outras funções.
#
#   -Adicionado no menu principal uma opção para verificar conectividade com
#   a internet.
# 
#
#TODO
#-Falta adicionar o programa em inglês, a chave já tem rs.
#-Falta adicionar a parte de Receber na opção Remoto
#-------END-HEADER-----------------------------------------------------------------|


#########################################################|
#################### VÁRIAVEIS ##########################|
#########################################################|
name="dunee"
version="0.2"
back="$name Versão $version"  # Titulo de fundo, para ser usado em --backtitle
directory_root="/etc/dunee"
log="/tmp/log.bkp"
log_tags="/tmp/log_tags.bkp"


#----CHAVES--------(bibibibi)
lang="0" # 0 pt_BR / 1 en_US 

#----COMANDOS---------------
date_bkp=$(date +%d-%m-%Y)  # Para criar a extensão nome-DATA.bkp

# Botões do dialog referente ao status de sáida.
cancel_button="1"
help_button="2"
esc_button="255"
#########################################################|



#########################################################|
################# TESTES de inicialização ###############|
#########################################################|

# Não é portugues do brasil? então ative a chave en_US
[[ "$LANG" = "en_US.UTF-8" ]] && lang="1" 

# Dialog existe?
if [[ ! -e $(type -P dialog) ]]; then             
   if [[ "$lang" -eq "1" ]]; then
      echo "DIALOG Not found..."
   else
      echo "Dialog não foi encontrado, instale e retorne."
   fi
fi   

# scp existe?
if [[ ! -e $(type -P scp) ]]; then              
  if [[ "$lang" -eq "1" ]]; then
      echo "scp Not found..."
  ecrilse
      echo "Não encontrei o scp..."
  fi
fi
#########################################################|



#########################################################|
#################### FUNÇÕES ############################|
#########################################################|

# Tela de ajuda principial do programa.
menu_welcome(){
  echo -e "\tpara ajuda digita !ajuda"
}


# Status global dos botões (cancel, help, esc)
status(){
case $? in
   "$cancel_button")
        dialog --title "$name"            \
        --backtitle "$back"               \
        --yes-label "Sim"                 \
        --no-label "Não"                  \
        --yesno "Deseja Sair?" 0 0
        [[ "$?" -eq "0" ]] && exit 0 ;;
        
    "$esc_button") echo "ESC, pressionado. :(" && exit 1 ;;
esac
}



# TAR Opções
execute_tar(){ tar -cvJpf "$@"; }


# SCP Opções
execute_scp(){
scp -C ${choose_the_tag} -P "$port" "$dir_if_backup" "${user}@${ip}:${dir_send}"
 }



if_dir(){
 while :; do
      name_backup=$(
          dialog --stdout                                                   \
          --title "IMPORTANTE!"                                             \
          --backtitle "$back"                                               \
          --cancel-label "Voltar"                                           \
          --inputbox                                                        \
          "Digite o Nome final para o Backup.\nExemplo Slackjeff-dir"       \
          10 50 )
          [[ "$?" -eq "1" ]] && main  # Apertou <VOLTAR> volta para o menu principal  

      # Verificando se váriavel nome do backup não está nula, se estiver loop nele.
      if [[ -z "$name_backup" ]]; then  
          dialog --title "OPS!"              \
          --backtitle "$back"                \
          --sleep 2                          \
          --infobox                          \
"\nVocê deixou nulo o nome do seu Backup.\n" \
          6 60  
      else
          dialog --title "NOME DO BACKUP FINAL"           \
          --backtitle "$back"                             \
          --sleep 2                                       \
          --infobox "\n${name_backup}-${date_bkp}.bkp"    \
          6 40
          break
      fi
 done
 
 # Vamos selecionar o diretorio/arquivo de ORIGEM
 while :; do  
      dir_if_backup=$(
          dialog --stdout                                      \
          --title "SELECIONE O DIRETÓRIO/ARQUIVO DE 'ORIGEM'"  \
          --backtitle "$back"                                  \
          --cancel-label "Voltar"                              \
          --dselect "/"                                        \
          8 80 )
          if [[ "$?" -ne "0" ]]; then
              # Apertou não? então voltamos ao menu principal!  
              dialog --title "RETORNANDO"                       \
              --backtitle "$back"                               \
              --sleep 2                                         \
              --infobox "\nOK, retornando ao menu principal..." \
              5 40
              main # Retornando ao menu principal            
          fi
          
          if ! dialog --title "CONFIRMA?"                                 \
               --backtitle "$back"                                        \
               --yes-label "Sim"                                          \
               --no-label "Não"                                           \
               --yesno "Confirma o diretório de 'ORIGEM': $dir_if_backup" \
               6 80
          then
               dialog --title "VOLTANDO"        \
               --backtitle "$back"              \
               --msgbox "Vamos retornar então." \
               5 40
          else
              # Usuário tem permissão de Leitura ou escrita no diretorio?
              # Se tiver para o loop e continua, se não volta.
              if [[ ! -w "$dir_if_backup" ]] || [[ ! -r "$dir_if_backup" ]]; then
text="\nSem permissões neste diretório...\n
Escolha outro diretório, ou dê as devidas permissões para este diretório."
                  dialog --title "SEM PERMISSÃO!"                          \
                  --backtitle "$back"                                      \
                  --msgbox "$text"                                         \
                  8 80
              else
                  break # Digitou sim o loop para e continua :)
              fi                         
          fi                                
    done   
}


of_dir(){
while :; do          
    # Agora vamos selecionar o diretorio/arquivo de DESTINO.
    dir_of_backup=$(
        dialog --stdout                                       \
        --title "SELECIONE O DIRETÓRIO/ARQUIVO DE 'DESTINO'"  \
        --backtitle "$back"                                   \
        --cancel-label "Voltar"                               \
        --dselect "/"                                         \
        8 80 )
    # Conferindo se usuário confirma.
              if [[ "$?" -ne "0" ]]; then
                   dialog --title "RETORNANDO"                       \
                   --backtitle "$back"                               \
                   --sleep 2                                         \
                   --infobox "\nOK, retornando ao menu principal..." \
                   5 40
                   main # Retornando ao menu principal    
              fi    
    
              if ! dialog --title "CONFIRMA?"                                         \
                   --backtitle "$back"                                            \
                   --yes-label "Sim"                                              \
                   --no-label "Não"                                               \
                   --yesno "Confirma o diretório de 'DESTINO': $dir_of_backup"    \
                   6 80
              then
                   # Apertou não? então voltamos ao menu principal! 
                  dialog --title "VOLTANDO"        \
                  --backtitle "$back"              \
                  --msgbox "Vamos retornar então." \
                  5 40
 
              else
                   # Usuário tem permissão de escrita no diretorio?
                   # Se tiver para o loop e continua, se não volta.
                   if [[ ! -w "$dir_of_backup" ]]; then
text="\nSem permissão de ESCRITA neste diretório...\n
Escolha outro diretório, ou dê permissão de ESCRITA 'w' para este diretório."                   
                        dialog --title "SEM PERMISSÃO!"  \
                        --backtitle "$back"              \
                        --msgbox "$text"                 \
                        8 80
                   else
                        break # Digitou sim o loop para e continua :)
                   fi              
              fi                                              
    done 
   # Se não tem '/' barra no final adiciona, se ter não faz nada.
   dir_of_backup_bar="${dir_of_backup%/}/" 
}



create_backup_basic(){
   # Gerando Backup, chamando a função (execute_tar)     
   execute_tar "${dir_of_backup_bar}${name_backup}-${date_bkp}.bkp" "$dir_if_backup" 2> /dev/null | \
   dialog --title "CRIANDO BACKUP..."                             \
   --backtitle "$back"                                            \
   --progressbox "Aguarde! criando backup em: $dir_of_backup_bar" \
   22 100
   # TODO Se apertar ESC retorna 1, precisa arrumar para retornar
   # status 255 para ter uma tela de falha com status 1.
   # Por enqaunto está generico com o case.
 case $? in
          1|130|255) status ;; # Monitoração, caso o usuário decida cancelar
                
           0) # Usuário quer gerar MD5?       
            if dialog --title "GERAR O MD5?"                \
               --backtitle "$back"                          \
               --yes-label "Sim"                            \
               --no-label "Não"                             \
               --yesno "\nVocê deseja gerar o arquivo md5?" \
               8 40     
            then 
                # Gerando MD5       
                dialog --title "GERANDO MD5!"                            \
                --backtitle "$back"                                      \
                --sleep 2                                                \
                --infobox "\nAguarde, vamos gerar o md5 e finalizamos."  \
                8 40
                
                if md5sum "${dir_of_backup_bar}${name_backup}-${date_bkp}.bkp" > "${dir_of_backup_bar}${name_backup}-${date_bkp}.md5"
                then 
                # Se deu tudo certo, mostramos a mensagem de ok e continuamos. 
                    dialog --title "CONCLÚIDO"               \
                    --backtitle "$back"                      \
                    --msgbox                                 \
"\nConclúimos, o md5 foi gerado em: '${dir_of_backup_bar}'"  \
                    8 40
                else
                    dialog --title "OPS"                 \
                    --backtitle "$back"                  \
                    --msgbox "Aconteceu algum erro ;("   \
                    8 40
                    main # Chamando função main.       
                fi           
            else
                dialog --title "CONTINUANDO"             \
                --backtitle "$back"                      \
                --sleep 2                                \
                --infobox "\nOk, vamos continuar sem md5." \
                6 40
            fi    
            
            # Mensagem de finalização!                
text="Finalizamos...\n
O arquivo '${name_backup}-${date_bkp}.bkp' está disponivel em '$dir_of_backup_bar'\n
Deseja fazer mais backup?"  
       if dialog --title "FINALIZADO!"  \
          --yes-label "Sim"           \
          --no-label "Não"            \
          --yesno "$text"             \
          8 100
       then
         # Se for sim, voltamos a função principal e começa tudo de novo! :)
         main # Chamando o menu principal.
       else
         echo -e "\033[31;1m ${name}<3 \033[m"
         exit 0
       fi                                                             
 esac # Case do MD5
}





#########################################################|
################### MODO BÁSICO #########################|
#########################################################|
basic_mod(){

#DIRETORIO DE ORIGEM
  if_dir # Chamada função de destino

# Diretório de DESTINO
  of_dir # Chamada função de DESTINO

# Criando Backup
  create_backup_basic # Chamada função para CRIAR backup, BÁSICO
                   
} # fecha função




#########################################################|
################## MODO REMOTO ##########################|
#########################################################|
remote(){
while :; do
  send_or_receive=$(
local text="Escolha a opção que se adapta a você!\n
-Para enviar um arquivo para um servidor remoto escolha a opção 'enviar'\n
-Para receber um arquivo de um servidor remoto escolha 'receber'\n"
  dialog --stdout                                                  \
         --title "ENVIAR OU RECEBER?"                              \
         --backtitle "$back"                                       \
         --ok-label "Confirma"                                     \
         --cancel-label "Voltar"                                   \
         --radiolist "$text"                                       \
         10 100 0                                                  \
         "Enviar" "Envie seus backups para um servidor remoto" on  \
         "Receber" "Receba seus backups de um servidor remoto" off \
)
[[ "$?" -eq "1" ]] && main # Aperto voltar, volta para o menu principal.

# Conferindo se var não está nula, se não estiver para o loop.
  if [[ -z "$send_or_receive" ]]; then
     dialog --title "OPS!" \
            --backtitle "$back" \
            --msgbox "Selecione alguma opção!" \
            0 0   
  else
     break             
  fi
done

case "$send_or_receive" in
   "Enviar") # Se for para enviar cai aqui! :)
      repete_form(){ 
      while :; do    
        text="TEXTO AQUI"
        # Armazenando dados do formulário em seu devido lugar.
        { read user; read ip; read port; read dir_send; }  \
             < <(dialog --stdout                           \
               --title "RESPONDA TODO FORMULÁRIO!"         \
               --ok-label "Enviar"                         \
               --cancel-label "Voltar"                     \
               --backtitle "$back"                         \
               --form "$text"                              \
               12 70  0                                    \
               "USUÁRIO:"            1 1   ""   1 13 35 0  \
               "IP HOST:"            2 1   ""   2 13 35 0  \
               "PORTA:"              3 1   "22" 3 13 10 0  \
               "DIRETORIO:"          4 1   ""   4 13 50 0  )
            # Conferindo status   
            [[ "$?" -eq "1" ]] && main # retornando ao menu
             
           # Conferindo váriaveis se não estão nulas.
           if [[ -z "$user" ]] || [[ -z "$ip" ]] || [[ -z "$port" ]] || [[ -z "$dir_send" ]]; then
text="\nParece que você deixou alguma informação nula!\n
É de extrema importância vocẽ preencher todos os campos.\n
Deseja retornar? e preencher os campos novamente?"
                if dialog --title "OPS!"     \
                    --backtitle "$back"       \
                    --yes-label "Sim"         \
                    --no-label "Não"          \
                    --yesno "$text"           \
                    10 60
                then     
                   dialog --title "RETORNANDO"   \
                   --backtitle "$back"           \
                   --sleep 2                     \
                   --infobox "\nVamos retornar." \
                   5 24
                else
                   main   
                fi
           else
                break    
           fi     
      done # Fecha while form

        # Verificando se usuário confirma os dados!
text="\nConfirma os dados fornecido no formulário?\n\n
Usuário: $user \n
Ip Host: $ip \n
Porta: $port \n
Diretório host: $dir_send \n"
          if ! dialog --title "CONFIRMA OS DADOS?" \
                 --backtitle "$back"               \
                 --yes-label "Sim"                 \
                 --no-label "Não"                  \
                 --yesno "$text"                   \
                 0 0
          then
              repete_form # Aperto nao? então chamamos o formulário de novo.
          fi
}
repete_form # Chamada função para formulário

choose_the_tag=$(
    dialog --stdout                                                                                         \
           --title "ESCOLHA AS OPÇÕES!"                                                                     \
           --backtitle "$back"                                                                              \
           --checklist ""                                                                                   \
           0 0 0                                                                                            \
           "-l" "Limitar o tamanho da banda"                                                            off \
           "-r" "Copie recursivamente diretórios inteiros."                                             off \
           "-p" "Preserva as horas de modificação, os tempos de acesso e os modos do arquivo original." off \
)

while :; do
  if echo "$choose_the_tag" | grep -q -o "\-l"; then
local text="Informe em quanto deseja limitar o tamanho da banda em Kbits
Somente Números! 100000 kbits = 1 mb"
    kbits=$(
       dialog --stdout \
              --title "INFORME"     \
              --backtitle "$back"   \
              --inputbox "$text"    \
              0 0
   )
    # Alterando a Váriavel para receber valor do kbits.
    echo "$choose_the_tag" > "$log_tags"
    choose_the_tag=$(sed "s/-l/-l $kbits/" "$log_tags")
  fi
  # Verificando se váriavel 'kbits' é númerica.
  numeric(){ echo "$@" | grep -q -v "[^0-9]"; }
      if ! numeric "$kbits"; then
          dialog --title "OPS."                          \
          --backtitle "$back"                            \
          --msgbox "Favor informe uma entrada NÚMERICA!" \
          5 50
      else
          break    
      fi
done   


# Bloco para escolher diretório de origem
while :; do  
    dir_if_backup=$(
             dialog --stdout                                      \
             --title "SELECIONE O DIRETÓRIO/ARQUIVO DE 'ORIGEM'"  \
             --backtitle "$back"                                  \
             --cancel-label "Voltar"                              \
             --dselect "/"                                        \
             8 80 )
             if [[ "$?" -ne "0" ]]; then
                dialog --title "RETORNANDO"                       \
                --backtitle "$back"                               \
                --sleep 2                                         \
                --infobox "\nOK, retornando ao menu principal..." \
                5 40
                main # Retornando ao menu principal 
             fi                      
                
                if ! dialog --title "CONFIRMA?"                                 \
                     --backtitle "$back"                                        \
                     --yes-label "Sim"                                          \
                     --no-label "Não"                                           \
                     --yesno "Confirma o diretório de 'ORIGEM': $dir_if_backup" \
                     6 80
                then
                     dialog --title "VOLTANDO"               \
                     --backtitle "$back"                     \
                     --msgbox "Vamos retornar então."        \
                     5 40
                     continue
                fi     
                # Usuário tem permissão de Leitura e escrita no diretorio?
                # Se tiver para o loop e continua, se não volta.
                if [[ ! -w "$dir_if_backup" ]] && [[ ! -r "$dir_if_backup" ]]; then
                    dialog --title "SEM PERMISSÃO!"                           \
                    --backtitle "$back"                                       \
                    --msgbox                                                  \
"\nSem permissões neste diretório...\n
Escolha outro diretório, ou dê as devidas permissões para este diretório."    \
                    8 80
                   else
                       break # Digitou sim o loop para e continua :)
                   fi                         
    done # Fecha loop principal
    
# Enviando arquivos para o Destino.
dialog --title "Digite O SEU PASSWORD!"                        \
       --sleep 1                                               \
       --infobox "Informe seu password para dar continuidade!" \
       0 0     
if execute_scp 2>"$log"; then
   dialog --title "CONCLUIDO"  \
          --back "$back"       \
          --msgbox "Concluido"
          0 0
else
   sed -i 's/scp/dunee/g' "$log"
   dialog --title "OPS."           \
          --backtitle "$back"      \
          --exit-label "Voltar"    \
          --textbox "$log" \
          0 0
   [[ -e "$log" ]] && rm "$log" # Existe? então remove arquivo de log em /tmp/       
fi   
     ;; # Fecha opção case enviar


   
    # Se for RECEBER cai aqui!|    
   "Receber") 
   remote_main
   
   if execute_scp 2>"$log"; then
      dialog --title "CONCLUIDO"  \
      --back "$back"       \
      --msgbox "Concluido"
      0 0
   else
      sed -i 's/scp/dunee/g' "$log"
      dialog --title "OPS."           \
      --backtitle "$back"      \
      --exit-label "Voltar"    \
      --textbox "$log" \
      0 0
     [[ -e "$log" ]] && rm "$log" # Existe? então remove arquivo de log em /tmp/       
   fi
     ;; # Fecha opção case enviar    
    

esac # Fecha case 'send_or_receive' PRINCIPAL
}



#########################################################|
################### INICIO ##############################|
#########################################################|

# Tela de boas vindas.
dialog --title "$name"                 \
       --backtitle "$back"             \
       --ok-label "Avançar"            \
       --msgbox                        \
"\nSeja bem vindo ao $name.\n
Nunca foi tão fácil fazer seus backups!\n
Caso você precise de ajuda entre na opção <AJUDA> para saber mais sobre
o $name"                               \
       10 80

# Menu principal,amarrado.
main(){
  while :; do
    menu=$(dialog --stdout                                              \
           --title "$name"                                              \
           --backtitle "$back"                                          \
           --help-button                                                \
           --help-label "Ajuda"                                         \
           --cancel-label "Cancelar"                                    \
           --menu                                                       \
"USE O <DIRECIONAL> PARA SE LOCOMOVER, <ESPAÇO> PARA SELECIONAR."       \
           0 0 0                                                        \
           "Básico" "Modo básico para um simples backup, (COMPACTADO)"  \
           "Remoto" "Envie/receba seus backup remotamente (SIMPLES)"    \
           "Conexão" "Testa se a conectividade com a internet."         \
           "Avançado" "Para um backup completo"                         )
#Verificando status de saida dos botões.
  case $? in
       "$help_button")
            dialog --title "MÓDULOS PRINCIPAIS"                    \
                   --backtitle "$back"                             \
                   --exit-label "Voltar"                           \
                   --textbox "$directory_root/menu-principal.txt"  \
                   20 100 ;;
       *)
         status ;; # status  chamada função status, botões globais (1, 255)
  esac

##################################################################################
# Verificando qual opção do menu o usuário selecionou (Básico, Remoto, Avançado) #
##################################################################################
 case $menu in
 
     Básico) basic_mod ;;
     
     
     Remoto) remote ;;
     
     
     Conexão) 
      #Conferindo se tem internet
local text="\nConferindo se há conexão com a internet."
      dialog --title "TESTE..." \
      --backtitle "$back"       \
      --infobox "$text"         \
      5 60
      if ! wget -q --spider www.google.com; then
local text="\nParece que você não há conexão com a internet.
Restabeleça uma conexão e retorne.\n\n
Caso você não tem o X disponivel, rode o comando logado como root:\n
# ifconfig -a\n
Veja a listagem e encontre a flag da sua rede...\n\n
Para conexões a cabo normalmente a tag inicia com 'eth'.\n
Para Wifi a tag inicia com 'wlan'.\n
Para dispositivo Android roteado 'usb'\n\n
Para estabelecer uma conexão você pode utilizar os comandos:
'dhcpcd opção flag_aqui' ou 'dhclient flag_aqui'"
          dialog --title "OPS!"   \
          --backtitle "$back"     \
          --msgbox "$text"        \
          18 100   
          main # Retornando ao menu principal  
      else
          dialog --title "OK!"                  \
          --backtitle "$back"                   \
          --ok-label "Prossiga"                 \
          --msgbox "\nConexão Estabelecida."    \
          7 35
      fi
    ;; 
     
     Avançado)
text="\nAguarde!\n
Está opção ainda não está disponivel no ${name}..."     
          dialog --title "Em criação." \
          --backtitle "$back"          \
          --msgbox "$text"             \
          8 60
    ;;   
 esac ###### case menu

done ###### fecha loop while pricipal
} ###### Fecha função main
main # Chamada função main. 

